package com.weibei.common.utils.jd;

import javax.crypto.Cipher;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class JdRSAUtil {

    public static final String  SIGN_ALGORITHMS = "SHA1WithRSA";

    /**加密算法RSA*/
    public static final String KEY_ALGORITHM = "RSA";

    /**RSA最大加密明文大小*/
    private static final int MAX_ENCRYPT_BLOCK = 117;

    /**RSA最大解密密文大小*/
    private static final int MAX_DECRYPT_BLOCK = 128;

    /**
     * RSA签名
     * @param content 待签名数据
     * @param privateKey 商户私钥
     * @param input_charset 编码格式
     */
    public static String sign(String content, String privateKey, String input_charset){
        try {
            PKCS8EncodedKeySpec priPKCS8 	= new PKCS8EncodedKeySpec(Base64_.decode(privateKey) );
            KeyFactory keyf 				= KeyFactory.getInstance(KEY_ALGORITHM);
            PrivateKey priKey 				= keyf.generatePrivate(priPKCS8);
            java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);
            signature.initSign(priKey);
            signature.update(content.getBytes(input_charset));
            byte[] signed = signature.sign();
            return Base64_.encode(signed);
        }catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * RSA验签名检查
     * @param content 待签名数据
     * @param sign 签名值
     * @param ali_public_key 支付宝公钥
     * @param input_charset 编码格式
     */
    public static boolean verify(String content, String sign, String ali_public_key, String input_charset){
        try {
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            byte[] encodedKey = Base64_.decode(ali_public_key);
            PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
            java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);
            signature.initVerify(pubKey);
            signature.update(content.getBytes(input_charset) );
            boolean bverify = signature.verify( Base64_.decode(sign) );
            return bverify;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 私钥解密
     * @param content 密文
     * @param private_key 商户私钥
     * @param input_charset 编码格式
     */
    public static String decrypt(String content, String private_key, String input_charset) throws Exception {
        PrivateKey prikey = getPrivateKey(private_key);
        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, prikey);
        InputStream ins = new ByteArrayInputStream(Base64_.decode(content));
        ByteArrayOutputStream writer = new ByteArrayOutputStream();
        //rsa解密的字节大小最多是128，将需要解密的内容，按128位拆开解密
        byte[] buf = new byte[128];
        int bufl;
        while ((bufl = ins.read(buf)) != -1) {
            byte[] block = null;
            if (buf.length == bufl) {
                block = buf;
            } else {
                block = new byte[bufl];
                for (int i = 0; i < bufl; i++) {
                    block[i] = buf[i];
                }
            }
            writer.write(cipher.doFinal(block));
        }
        return new String(writer.toByteArray(), input_charset);
    }

    /**
     * 公钥加密
     * @param data 源数据
     * @param publicKey 公钥(BASE64编码)
     */
    public static byte[] encryptByPublicKey(byte[] data, String publicKey) throws Exception {
        byte[] keyBytes = Base64_.decode(publicKey);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicK = keyFactory.generatePublic(x509KeySpec);
        // 对数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicK);
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段加密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        return encryptedData;
    }

    public static String encryptByPublicKeyToStr(byte[] data, String publicKey) throws Exception {
        byte[] bytes = encryptByPublicKey(data, publicKey);
        String result = Base64_.encode(bytes);
        return result;
    }

    /**
     * 得到私钥
     * @param key 密钥字符串（经过base64编码）
     * @throws Exception
     */
    public static PrivateKey getPrivateKey(String key) throws Exception {
        byte[] keyBytes;
        keyBytes = Base64_.decode(key);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
        return privateKey;
    }

    public static class Base64_ {
        private static final Base64.Decoder decoder = Base64.getDecoder();
        private static final Base64.Encoder encoder = Base64.getEncoder();
        public static byte[] decode(String key) {
            if (key == null) { return null;}
            byte[] decode = decoder.decode(key);
            return decode;
        }
        public static String encode(byte[] content) {
            if (content == null) {return null;}
            String encode = encoder.encodeToString(content);
            return encode;
        }
    }

    /**
     * 测试
     */
    public static void main(String args[]) throws Exception{
//        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
//        keyPairGen.initialize(1024);
//        KeyPair keyPair = keyPairGen.generateKeyPair();
//        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
//        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
//        String pubKey = Base64_.encode(publicKey.getEncoded()); //公钥
//        String priKey = Base64_.encode(privateKey.getEncoded()); //私钥
        String pubKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCt3VPJq6Y66nNDivdgXVoSubOiuF0VVzcg0gYwHOW7Tj0diDyQaGHINMv8LNk1wZg58yzP9H4zWWRMsgbCEIqB8Vz3AWuTG+RKupBBE3Zc/vbgrYYHEgUDhJrPslP9Oqhscz5tqKjBekiJfXnaod9k6jZr2cTXcdW06hzWJ0q4YwIDAQAB";
        String priKey = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAIwJs2ZBzKQY5MMGLJ+KK8NnFF3GirwExWEVgrylkePyAoXxwMQfO4txK0M/Z5vAd0VBZRjChkpCDezjnj2SeMrNjMOQq3dMahXuvOXP1ZXmzhsP5KILPUuL03OChQrrWRYemMSiZPO1ocwZcOO3qhluGUaw4KoyFl6lX+SQTvnnAgMBAAECgYAF45KLxlCYxgM4wFW4D9NvUDJnDyZeacTzJDhvPnc4IsFAaL42gSm733J2TYBJ6Hobi3h45hVHoid7wsawyCwUK0O2KixIM7Z70YRObd7DrlGoR6Q86XGgCEhro5bXsI3+gfHdQ4IzDuLHK0XxTZCaUolirO+A0dfEo5SqL57kQQJBAMnItJf4ScBlroBh2BTLvPxbkpm5rnL6OCoCOYaJeBcvZdqMHC7dHhnHOgf8kOQYciQ/cguZVvWO70PBIxWYrF8CQQCxqerBe5iN/z7uh6UfPzT111qj0hlWQvBHZRyhdv8BtRumeffWCsESlIcaRLYTq6wy130ddZsxU+4kMVrneh95AkEAizUxCgrb7qT3r1BRP3+TYNJYID/Ojzn611hzkVJzjCNB9HVm2BnqM0STz4C6APKwhDtVFZVzPbOfc7Hh33tVpwJBAKT4qdNF6E+afx5Q+IP+Vjgd472Q3xQZjjJNcnuAGqTEPkukn/yx+bw+DQHYYdX8KCcBr90GEriIPe5/ofCllskCQQCC/dbgq6zOa0wWw3T1TcS2g/Cy6EBZ19HvmanVATT4eeo/wmq0bQUN0FuzSM23hexf3/4zKintGZ+KgInhAB62";

//        System.out.println(pubKey);
//        System.out.println(priKey);

//......................................公钥加密，私钥解密！

        String fullStr = "123456";
        fullStr = fullStr.substring(0,fullStr.length() -1);
        System.out.println(fullStr);

        String sourceStr = "oR9LI1KyTypwdLevJudkOf7gMGgg";
        //公钥加密
//        byte[] ens = JdRSAUtil.encryptByPublicKey(sourceStr.getBytes(),pubKey);
//        String encodes = Base64_.encode(ens);
//        System.out.println(encodes);
        String encodes = JdRSAUtil.encryptByPublicKeyToStr(sourceStr.getBytes(), pubKey);
        System.out.println(encodes);
        //私钥解密
//        String res2 = JdRSAUtil.decrypt(encodes, priKey, "UTF-8");
//        System.out.println(res2);

        //......................................私钥加密，公钥解密！

//        String sourceStr = "我是中国人啊!!!!!!!!!!!!!!!!!!!!!!!!!";
//        //公钥加密
//        byte[] ens = RSAUtil.encryptByPublicKey(sourceStr.getBytes(),pubKey);
//        String encodes = Base64_.encode(ens);
//        System.out.println(encodes);
//        //私钥解密
//        String res2 = RSAUtil.decrypt(encodes, priKey, "UTF-8");
//        System.out.println(res2);

//.......................................签名验证，私钥签名，公钥验证是否正确!

        String source = "accessKey=L_58I7LjXhaQXU9FLNP6Ug==&extend={\"currentAsset\":\"10.00\",\"customerShow\":\"true\",\"phone\":\"13520559575\",\"userName\":\"醉了\"}&returnUrl=https://jfd-m.jd.com/fuli_page_wegoIndex&timestamp=1605180089035&uid=oR9LI1KyTypwdLevJudkOf7gMGgg"; //模拟请求参数,然后对此请求参数进行签名。
//
//        String sign = JdRSAUtil.sign(source, priKey, "UTF-8");
//
//        System.out.println("签名是："+sign);

        String sign = "dgLteXxei6aV+fVY8yL5WjjbD5KQgdB4LEOum/iufVIkPCnZvugFwhmmfvfC8pVYDtvu/Lj7xX/9enZrQq30YRHjiR3Sp2N7fft4k4Qj6H1NQyV6b/p7Zu+UhLjYAV6mgNKehOuCDHPZZRRDDglZKX2Kb1PtD9sLx31pr7+PTtc=";

        // 公钥验证签名是否正确.
        // 具体流程是，请求参数+sign发送给公钥方，然后公钥方过滤掉sign，用公钥验证其他参数是否通过。

        boolean result = JdRSAUtil.verify(source, sign, pubKey, "UTF-8");

        System.out.println(result);

    }
}
